package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"strconv"
)

type TracksChaincode struct {

}

type Track struct {
	Id int64 `json:"id"`

	UserId int64 `json:"userId"`
	UserName string `json:"userName"`
	Avatar string `json:"avatar"`

	Content string `json:"content"`
	Location string `json:"location"`
	LocationName string `json:"locationName"`

	UpCount int `json:"upCount"`
	DownCount int `json:"downCount"`
	Status int `json:"status"`
	ImageList []string `json:"imageList"`
	CreateTime string `json:"createTime"`
}

func main() {
	err := shim.Start(new(TracksChaincode))
	if err != nil {
		fmt.Errorf(err.Error())
	}
}

func (t TracksChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}

func (t TracksChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {

	fc, args := stub.GetFunctionAndParameters()

	if fc == "add" {
		return t.Add(stub, args)
	} else if fc == "get" {
		return t.Get(stub, args)
	} else if fc == "batchAdd" {
		return t.BatchAdd(stub, args)
	}

	return shim.Error(fmt.Sprintf("function is not found: %s", fc))
}

func (t TracksChaincode) Add(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 {
		return shim.Error(parameterErr.Error())
	}

	var track Track
	if err := json.Unmarshal([]byte(args[0]), &track); err != nil {
		return shim.Error(err.Error())
	}

	if err := saveTrack(stub, track); err != nil {
		return shim.Error(err.Error())
	}

	return success
}

func (t TracksChaincode) BatchAdd(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 {
		return shim.Error(parameterErr.Error())
	}

	var tracks []Track
	if err := json.Unmarshal([]byte(args[0]), &tracks); err != nil {
		return shim.Error(err.Error())
	}

	for _, track := range tracks {
		if err := saveTrack(stub, track); err != nil {
			return shim.Error(err.Error())
		}
	}

	return success
}

func (t TracksChaincode) Get(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		return shim.Error(parameterErr.Error())
	}

	userId, id := args[0], args[1]
	queryId, err := stub.CreateCompositeKey(userId, []string{id})
	if err != nil {
		return shim.Error(err.Error())
	}
	tb, err := stub.GetState(queryId)
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(tb)
}


func saveTrack(stub shim.ChaincodeStubInterface, track Track) error {
	id, err := stub.CreateCompositeKey(strconv.FormatInt(track.UserId, 10), []string{strconv.FormatInt(track.Id, 10)})
	if err != nil {
		return err
	}
	tb, err := json.Marshal(track)
	if err != nil {
		return err
	}
	return stub.PutState(id, tb)
}

func getTrack(stub shim.ChaincodeStubInterface, id string) (track Track, err error) {
	tb, err := stub.GetState(id)
	if err != nil {
		return
	}
	err = json.Unmarshal(tb, &track)
	if err != nil {
		return
	}
	return
}

var parameterErr = errors.New("parameter err")

var success = shim.Success([]byte("success"))